﻿#ifndef _DB_H
#define _DB_H
#pragma once
#include<iostream>
#include"json.h"
#include<ctime>
#include<string>
#include"sqlite3.h"
#include<vector>
#include<sstream>
#include<map>
#include <windows.h>

//#include "Room.h"

#define MAX_TEMPRATURE 30
#define DEFAULT_TEMPRATURE 26
#define MIN_TEMPRATURE 18

enum class RecordType :int { NONE = 0, USEROPERATION = 1, SERVICESTART = 2, SERVICEEND = 3 };
enum class WindMood :int { NONE, LOW, MEDIUM, HIGH };
enum class FanSpeed :int { LOW = 1, MEDIUM, HIGH };
enum class Identity :int { NONE, GUEST, MANAGER, RECEPTIONIST, ACMANAGER };
enum class IdentityR :int { CLIENT = 1, MANAGER, RECEPTION, ADMIN };
enum class OptionType :int { NONE, ON = 1, OFF = 2, CHANGET = 3, CHANGEW = 4 };
enum class Type :int { QUERY, RESPONSE, NONE };
enum class QueryType :int { DETAIL, PAYMENT, DEFAULT, STATEMENT, CHANGEDEFAUL, ROOM, CHANGEROOM, AUTH, INSERT, ONOFF, WINDSTOP, WINDSTART };
enum class ResponseType :int { DETAIL, PAYMENT, DEFAULT, STATEMENT, ROOM, AUTH };
enum class RoomState :int { SERVING = 1, WAITING, POWEROFF, SLEEPING };

class Record {
private:
    time_t time;    //当前时间
    Type type; //表示是query还是response
    Identity source;
    QueryType queryType;
    int roomId;     //房间号
    int recordId;   //记录号
    RecordType recordType;   //记录类型，1(用户操作请求)  2(进服务队列)  3(出服务队列)
    double currentT;      //房间当前温度
    WindMood currentW; //房间当前风速
    double requestT;      //房间请求温度
    WindMood requestW; //房间请求风速
    OptionType optionType; //房间操作，1代表开机 2代表关机 3 代表调温 4代表调风
public:
    Record() {
        queryType = QueryType::INSERT;
        setTime(0);
        setRoomId(-1);
        setRecordId(-1);
        setRecordType(RecordType::NONE);
        setCurrentT(0);
        setCurrentW(WindMood::NONE);
        setRequestT(0);
        setRequestW(WindMood::NONE);
        setOptionType(OptionType::NONE);
        setType(Type::NONE);
        setSource(Identity::NONE);
    }

    time_t getTime(void);
    QueryType getqueryType(void);
    int getRoomId(void);
    int getRecordId(void);
    RecordType getRecordType(void);
    double getCurrentT(void);
    WindMood getCurrentW(void);
    double getRequestT(void);
    WindMood getRequestW(void);
    OptionType getOptionType(void);
    Type getType(void);
    Identity getSource(void);

    void setTime(time_t t);
    void setRoomId(int Id);
    void setRecordId(int Id);
    void setRecordType(RecordType t);
    void setCurrentT(double rt);
    void setCurrentW(WindMood rw);
    void setRequestT(double rt);
    void setRequestW(WindMood rw);
    void setOptionType(OptionType ot);
    void setType(Type ty);
    void setSource(Identity identity);
};

class reqPayment { //用于查询账单的返回值
public:
    int recordId;
    time_t time;
    WindMood wd;
};
class reqDetail {
public:
    time_t time;
    OptionType ot;
    double rt;
    WindMood rw;
};
class reqStatement {
public:
    int ACUserCount;    //所有房间使用空调次数
    int roomId;
    double roomCommonTemp;     //该房间最常用目标温度
    WindMood roomCoomonWind; //该房间达到目标温度的次数
    int roomReachTempCount; //该房间达到目标温度次数
    int roomServiceCount;   //该房间被调度次数  
    int roomRecordCount;    //该房间详单记录数
    double totalfee;
};

class RecordBean {
private:
    const char* dataPath = "RecordBean.db"; //表示数据库的名字
    sqlite3* db;
public:
    sqlite3_stmt* stmt = NULL; //stmt语句句柄
    RecordBean();
    bool insert(Record* rd); //插入成功返回true，失败返回false
    std::vector<reqStatement*> query3(time_t endTime, time_t startTime);  // 请求报表
    std::vector<reqPayment*> query1(int roomId); // 请求账单
    std::vector<reqPayment*> query1(int roomId, time_t startTime, time_t endTime);//重载，算特定时间内的账单
    std::vector<reqDetail*>  query2(int roomId); // 请求详单，暂定加个bool为详单的重载函数
    void closeDB(void);
};

class PaymentList {
private:
    time_t time;
    Type type;
    int responseType;
    int listId;
    int roomId;
    double totalFee;

public:
    PaymentList(int roomId, int listId, std::vector<reqPayment*>req);
    time_t gettime(void);
    Type gettype(void);
    int getresponseType(void);
    int getlistId(void);
    int getroomId(void);
    double gettotalFee(void);

    double settotalFee(std::vector<reqPayment*>req);
};

class DetailList {
private:
    time_t time;
    Type type;
    int responseType;
    int listId;
    int roomId;
    std::vector<std::string> info;

public:
    DetailList(int roomId, int listId, std::vector<reqDetail*>req);
    time_t gettime(void);
    Type gettype(void);
    int getresponseType(void);
    int getlistId(void);
    int getroomId(void);
    std::vector<std::string> getinfo(void);
    std::vector<std::string> setinfo(std::vector<reqDetail*>req);
};
class DBFacade {
private:
    int paymentNumber;
    int detailNumber;
public:
    DBFacade();
    DBFacade(int diff);
    Json::Value getMapper(Json::Value detailList);
    //bool getMapper(Room rd);
    //bool getMapper(User rd);
    int getpaymentNumber(void);
    int getdetailNumber(void);
    void adddetailNumber(void);
    void addpaymentNumber(void);
    void insertRecord(Record* rd);
    double getRoomBill(int roomId);
    Json::Value getDetailList(int newId); //找详单
    Json::Value getStatement(time_t startTime, time_t endTime); //找报表
    Json::Value getpayment(int newId); //找账单

    std::vector<Json::Value> to_schedule_list;
    Json::Value RoomQuery(Json::Value val);
    void RoomTemperature(std::vector<Json::Value>* ptr);
    void RoomScan(std::vector<Json::Value>& list);
    static void RoomScanTimer(LPVOID list);
    Json::Value RoomResponse(Json::Value val);
};

class Statement {
private:
    time_t time;
    time_t startTime;
    time_t endTime;
    Type type;
    int responseType;
    int ACUseCount;
    std::vector<std::string>info;
public:
    Statement(time_t startTime, time_t endTime, std::vector<reqStatement*>req);
    time_t gettime(void);
    time_t getstartTime(void);
    time_t getendTime(void);
    Type gettype(void);
    int getresponseType(void);
    int getACUseCount(void);
    std::vector<std::string> getinfo(void);
    std::vector<std::string> setinfo(std::vector<reqStatement*>req);
};

extern DBFacade* dbfacade;
class Statistic {
public:
    Json::Value query(Json::Value);
};

class AuthenticationBean {
private:
    std::string dataPath = "test.db";
public:
    bool Insert();
    bool Delete();
    bool Update();
    Json::Value Query(Json::Value query);
};

#endif

class Room {
private:
    time_t _time;//current
    Type _type;//q or r
    IdentityR _source;
    IdentityR _destination;
    QueryType _queryType;
    ResponseType _responseType;
    int _roomId;
    RoomState _state;
    double _targetT;//from scheduler
    FanSpeed _targetW;//from scheduler
    double _nowT;//from db
    FanSpeed _nowW;//from db
    double _initT;
    double _fee;//from recordBean
    int _power;//from scheduler
public:
    Room(void);
    ~Room() = default;

    bool deleteInfo(Json::Value val);
    bool getInfo(Json::Value val, Json::Value& response);
    bool changeInfo(Json::Value val);
    bool changePower(Json::Value val);
    int editTemperature(void);
    std::string pack(Json::Value);

    time_t getTime(void);
    Type getType(void);
    IdentityR getSource(void);
    IdentityR getDestination(void);
    QueryType getQueryType(void);
    ResponseType getResponseType(void);
    int getRoomId(void);
    RoomState getRoomState(void);
    double getTargetT(void);
    FanSpeed getTargetW(void);
    double getCurrentT(void);
    FanSpeed getCurrentW(void);
    double getInitT(void);
    double getBill(void);
    int getPower(void);

    void setTime(time_t time);
    void setType(Type type);
    void setSource(IdentityR src);
    void setDestination(IdentityR des);
    void setQueryType(QueryType query);
    void setResponseType(ResponseType rsp);
    void setRoomId(int id);
    void setRoomState(RoomState state);
    void setTargetT(double t_temp);
    void setTargetW(FanSpeed t_wind);
    void setCurrentT(double c_temp);
    void setCurrentW(FanSpeed c_wind);
    void setInitT(double i_temp);
    void setBill(double bill);
    void setPower(int power);

    //change wind/temp/power
    //get info/bill

    //DBFacade receives a query, then initialize a room with it
    //with a DBFacade::function
    //roombean is a global unique one(?)
    //the room decide which bean-method to use with json::value
    //one Room::function to judge the query type and use the functions below
    //wind: setCurrentW, then setCurrentT and Update every 60 secs
    //temp: setCurrentT, then Update
    //power: same
    //info: Query, then return a json::value
    //bill: not decided
};

class RoomBean {
private:
    const char* dataPath = "RoomBean.db";
    sqlite3* roomDatabase;
public:
    sqlite3_stmt* stmt = NULL;
    RoomBean();
    ~RoomBean();
    bool Insert(Room* room);
    bool Update(Room* room);
    bool Update_power(Room* room);
    bool Update_temp(Room* room);
    bool Delete(Room* room);
    bool Query(Room* room);
    bool Query(std::vector<int>& roomlist);
};